#include <memory>

#include "graph_support/utils/test_my_graph/BoostTestUtils.h"

#include "common/TestLanguageFeatures.h"
#include "graph_support/TestDejkstra.h"
#include "graph_support/TestCommonGraphFeatures.h"
#include "graph_support/TestFlowGraph.h"
#include "graph_support/TestGraphUniversal.h"
#include "graph_support/TestKnightWalksOnChessBoard.h"
#include "graph_support/TestGraphTraversal.h"
#include "graph_support/TestLanguageIssues.h"
#include "graph_support/TestIGraph.h"
#include "graph_support/test_gs_version/TestGSVersion.h"
#include "graph_support/alg_correctness_tests/TestBorderCondition.h"
#include "graph_support/alg_correctness_tests/dinic_alg_tests/TestDinicAlgCorrectness.h"
#include "graph_support/TestMinCostFlow.h"
#include "graph_support/TestGraphDecorators.h"


namespace GRAPH_SUPPORT_NS_boost_test_suit
{

class TestSuite : public boost::unit_test::test_suite
{
public:
	TestSuite( const char * name )
		: boost::unit_test::test_suite( name )
	{
	}
};

}
using namespace GRAPH_SUPPORT_NS_boost_test_suit;

namespace
{

void suiteTestCommonGraphFeatures( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestCommonGraphFeatures" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestGraphSize ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestSmartVert2num ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestZEROGraphSize ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestPureNegVertices ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestMixedIntVerticesGraphGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestIntVertices ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCharVertices ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCastWrap2Vert ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestSTDStringVertices ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestForEachOutcomeEdge ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestBidirGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestBusinessGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestBusinessGraphDinic ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestMatrixGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestEdgeOverflowForCompactGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestEdgeOverflowForCompactGraph_FlowNet ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestDejkstra( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestDejkstra" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestEdgesConnection ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestDistanceSearch ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCharVerticesDejkstra ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestFlow( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestFlow" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestFlowRevertedEdges ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestDinic ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestCommon( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestCommon" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestBoostObjectPool ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestComputeCollLength ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestSameFn ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestPtrAccessOperator ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRTTIOn ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestUnified( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestRunUniversalTest4MatrixGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRunUniversalTest4VectorGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRunUniversalTest4CompactGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRunUniversalTest4KnightsWalking ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestChessboard( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestKnightsFirstStepWalking ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestAddressesOfEdgeAttributes ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestGraphTraversal( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestGraphBFS ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestGraphBFSDuplicateVertices ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestGraphDFS ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestLanguageIssues( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestStoreGraphVertexPointers ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestResolveTableType ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCastOperator ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestPtr2ref ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRTTIStorageTemplate ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestRTTICopyStorageTemplate ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestGSVersion( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestTrivialDejkstraAfterGSIncludeMacros ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestTrivialDejkstraHardcodeVersion ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestAlgCorrectness( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestDinicOnFullGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestBFSTraversalOnFullGraph ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestCompareStupidDinicWithOfficial ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestDinicAlgCorrectness ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestMinCostFlowAlgCorrectness ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestIGraph( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestVertexCount ) );
//	graphTestSuite->add( BOOST_TEST_CASE( & TestIterateEdges ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestIteratorInteface ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestIAttributesChange ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestFlowOnIGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestWrap4IGraph ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestBFSOnIGraph ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestMinCostFlow( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestUniversal" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestCostFlowAttributes ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCostFlowChepExpensive ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCostFlowNegativeCycleCancel ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestCostFlowNegativeCycleWithChild ) );

	suite->add( graphTestSuite.release() );
}

void suiteTestGraphDecorators( boost::unit_test::test_suite * suite )
{
	std::auto_ptr< TestSuite > graphTestSuite( new TestSuite( "SuiteTestGraphDecorators" ) );

	graphTestSuite->add( BOOST_TEST_CASE( & TestJoinTwoGraphs ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestJoinMultipleGraphs ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestConvertAttributesDecorator ) );
	graphTestSuite->add( BOOST_TEST_CASE( & TestConvertAttributesDecoratorOnStoreFlow ) );

	suite->add( graphTestSuite.release() );
}

}

boost::unit_test::test_suite * init_unit_test_suite( int argc, char * * argv )
{
	boost::unit_test::test_suite * suite( BOOST_TEST_SUITE( "Master Suite" ) );

	suiteTestCommonGraphFeatures( suite );
	suiteTestDejkstra( suite );
	suiteTestFlow( suite );
	suiteTestCommon( suite );
	suiteTestUnified( suite );
	suiteTestChessboard( suite );
	suiteTestGraphTraversal( suite );
	suiteTestLanguageIssues( suite );
	suiteTestGSVersion( suite );
	suiteTestIGraph( suite );
	suiteTestMinCostFlow( suite );
	suiteTestGraphDecorators( suite );

	suiteTestAlgCorrectness( suite );

	return suite;
}
